/*
 * Created on 2005-3-4
 */
package com.hd123.rumba.request;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.Enumeration;
import java.util.StringTokenizer;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import net.sf.hibernate.HibernateException;

import org.apache.log4j.Logger;

import com.hd123.rumba.qt.QueryResultSession;
import com.hd123.rumba.qt.QuerySourceSession;
import com.hd123.rumba.runtime.Configuration;
import com.hd123.rumba.runtime.HibernateSession;
import com.hd123.rumba.runtime.Runtime;
import com.hd123.rumba.util.ObjectUtil;
import com.hd123.rumba.util.StopWatch;
import com.hd123.rumba.util.StringUtil;

/**
 * @author caili
 */
public class RequestHandler extends HttpServlet {

  private boolean bGenRequestScript = false;

  private String requestScriptDir = null;
  public static String applicationName = "RUMBA";

  protected String getLicenseName() {
    return applicationName;
  }

  public void init(ServletConfig config) throws ServletException {
    super.init();
    String name = (String) config.getInitParameter("name");
    if (name != null && name.trim().length() > 0) {
      applicationName = name;
    }
    bGenRequestScript = "true".equals(config.getInitParameter("genRequestScript"));
    requestScriptDir = config.getInitParameter("requestScriptDir");
    try {
      Configuration.getInstance().config(config);
    } catch (Exception e) {
      throw new ServletException(e);
    }
  }

  protected void doGet(HttpServletRequest request, HttpServletResponse response)
      throws ServletException, IOException {
    processRequest(request, response);
  }

  protected void doPost(HttpServletRequest request, HttpServletResponse response)
      throws ServletException, IOException {
    processRequest(request, response);
  }

  protected void processRequest(HttpServletRequest request, HttpServletResponse response)
      throws ServletException, IOException {
    request.setCharacterEncoding(StringUtil.ENCODING_CHARSET);
    response.setCharacterEncoding(StringUtil.ENCODING_CHARSET);

    Logger logger = Logger.getLogger("com.hd123.rumba.TIME");
    String url = null;
    Dictionary dd = null;
    StopWatch sw = null;
    String qs = StringUtil.decodePathInfo(request.getQueryString());
    try {
      logger.debug(request.getRemoteHost() + ": " + request.getRequestURI() + "?" + qs + " !@# "
          + request.getSession().getId());
      sw = new StopWatch().start();
      dd = new Dictionary(request, response);
      request.setAttribute("dd", dd);

      // 记录请求脚本
      generateRequestScripts(dd);

      String actionName = request.getPathInfo().replace('/', '.');
      // String startnode = dd.getStartNode();
      // String aclName = startnode == null ? actionName : actionName + "." +
      // startnode;
      // if (ActionAcl.getInstance().hasAcl(dd.getCurrentUser(), aclName)) {
      Action action = null;
      try {
        action = (Action) findAction(actionName);
      } catch (ClassNotFoundException e) {
        dd.setWorkingTemplate(ActionConstants.NOTIMPLEMENTED);
        url = ActionConstants.APPLICATIONFRAME;
      }
      if (action != null) {
        action.init(dd);
        url = action.execute();
      }
      // } else {
      // dd.setWorkingTemplate(ActionConstants.NOACCESS);
      // url = ActionConstants.APPLICATIONFRAME;
      // }
      if (!url.equals(ActionConstants.DIRECT)) {
        url = JspLib.getTemplate(url);
        RequestDispatcher rd = request.getSession().getServletContext().getRequestDispatcher(url);
        rd.forward(request, response);
      }
    } catch (Throwable ex) {
      Throwable e = ex;
      if (e instanceof InvocationTargetException) {
        e = ((InvocationTargetException) e).getTargetException();
      }
      // ByteArrayOutputStream os = new ByteArrayOutputStream();
      // e.printStackTrace(new PrintStream(os));
      // logger.error(os.toString());
      logger.error("", e);
      dd.put("exception", e);
      url = JspLib.getTemplate("application/GeneralError.jsp");
      RequestDispatcher rd = request.getSession().getServletContext().getRequestDispatcher(url);
      rd.forward(request, response);
    } finally {
      try {
        HibernateSession.closeSession();
        if (dd != null && !dd.containsKey("KeepQuerySourceAndResultSessions")) {
          QuerySourceSession.closeSession();
          QueryResultSession.closeSession();
        }
      } catch (HibernateException e) {
        logger.error(e);
      }
      if (sw != null)
        logger.info("perf|" + sw.stop() + "|" + request.getRemoteHost() + "|"
            + request.getRequestURI() + "?" + qs + "|" + request.getSession().getId());
    }
  }

  private Action findAction(String actionName) throws ClassNotFoundException,
      InstantiationException, IllegalAccessException {
    StringTokenizer pacs = new StringTokenizer(ActionConstants.ACTIONPACKAGE, ";");
    Class clazz = null;
    while (pacs.hasMoreTokens()) {
      try {
        clazz = Class.forName(pacs.nextToken() + actionName);
        break;
      } catch (ClassNotFoundException e) {
      }
    }
    if (clazz == null)
      throw new ClassNotFoundException(actionName + " in " + ActionConstants.ACTIONPACKAGE);
    Action action = (Action) clazz.newInstance();
    return action;
  }

  private void generateRequestScripts(Dictionary d) throws Exception {
    if (!bGenRequestScript)
      return;
    Logger logger = Logger.getLogger(this.getClass());
    HttpServletRequest rep = d.getRequest();
    File dir = new File(requestScriptDir);
    dir.mkdir();
    File file = new File(dir, rep.getRequestURI().substring(
        rep.getRequestURI().lastIndexOf("/") + 1, rep.getRequestURI().length())
        + ".script");
    FileOutputStream out = new FileOutputStream(file, true);
    String key, name, value = "";
    String user_login = null;
    String reqUrl = rep.getRequestURL().toString();
    if (d.getCurrentUser() != null)
      user_login = "client:" + d.getCurrentUser().getLogin() + "\r";
    try {
      // out.write("runpass=2\r".getBytes());
      // out.write("<comment>\r".getBytes());
      // out.write((reqUrl + "\r").getBytes());
      // out.write("</comment>\r".getBytes());
      if (user_login != null)
        out.write(user_login.getBytes());
      out.write(("  url:" + reqUrl + "\r").getBytes());
      out.write(("  method:" + rep.getMethod() + "\r").getBytes());
      Enumeration e = d.getFormValues().keys();
      while (e.hasMoreElements()) {
        key = (String) e.nextElement();
        name = "  param:" + key + "=";
        value = JspLib.format((Object) d.getFormValues().get((key)));
        out.write((name + value + "\r").getBytes());
        out.flush();
      }
    } catch (Exception e) {
      logger.error(e);
    } finally {
      out.close();
    }
  }
}
